package com.zhiwei.codesecurity.common.utils;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.wc.*;

import java.io.File;
import java.io.OutputStream;

public class SVNUtils {
    private static Logger logger = LoggerFactory.getLogger(SVNUtils.class);
    private SVNClientManager svnClientManager;

    /**
     * 通过不同的协议初始化版本库
     */
    static  {
        DAVRepositoryFactory.setup();
        SVNRepositoryFactoryImpl.setup();
        FSRepositoryFactory.setup();
    }

    /**
     * 使用用户名与密码创建一个Svn客户端
     * @param username
     * @param password
     */
    public SVNUtils(String username, String password) {
        DefaultSVNOptions options = SVNWCUtil.createDefaultOptions(false);
        svnClientManager = SVNClientManager.newInstance(options, username, password);
    }


    /**
     * 将指定版本库文件夹路径的最新版本检出到本地
     * @param repoPath
     *          仓库路径 url，必须是文件夹
     * @param workingCopy
     *          本地工作副本，必须是文件夹
     * @param includeChildren
     *          是否检出文件夹下的文件和子文件夹
     * @throws SVNException
     *          当repoPath或workingCopy不是文件夹时，或者repoPath不存在时，抛出该异常
     */
    public void checkout(String repoPath, File workingCopy, boolean includeChildren) {
        try {
            SVNUpdateClient client = svnClientManager.getUpdateClient();
            SVNURL repositoryURL = SVNURL.parseURIEncoded(repoPath);
            SVNDepth depth = includeChildren ? SVNDepth.INFINITY : SVNDepth.EMPTY;
            client.doCheckout(repositoryURL, workingCopy, SVNRevision.HEAD, SVNRevision.HEAD, depth,
                    true);
        } catch (SVNException ex) {
            logger.error(">>>>>>>>>获取SVN扫描代码异常:{}", ex.getMessage());
        }
    }

    /**
     * 更新版本化环境中的工作副本到最新版本
     * @param workingCopy
     *          本地工作副本，可以是文件或文件夹
     * @param includeChildren
     *          当workingCopy是文件夹时，是否检出文件夹下的文件和子文件夹
     * @throws SVNException
     */
    public void update(File workingCopy, boolean includeChildren) throws SVNException {
        SVNUpdateClient client = svnClientManager.getUpdateClient();
        SVNDepth depth = includeChildren ? SVNDepth.INFINITY : SVNDepth.EMPTY;
        client.doUpdate(workingCopy, SVNRevision.HEAD, depth, true, true);
    }

    /**
     * 添加工作副本到版本化环境中
     *
     * @param workingCopy
     *            本地工作副本，可以是文件或文件夹
     * @param includeChildren
     *            是否添加文件夹下的文件和子文件夹
     * @throws SVNException
     */
    public void add(File workingCopy, boolean includeChildren) throws SVNException {
        SVNWCClient client = svnClientManager.getWCClient();
        SVNDepth depth = includeChildren ? SVNDepth.INFINITY : SVNDepth.EMPTY;
        client.doAdd(workingCopy, true, false, true, depth, false, true);
    }

    /**
     * 提交已添加到版本化环境中的工作副本到版本库
     *
     * @param includeChildren
     *            是否添加文件夹下的文件和子文件夹
     * @param commitMessage
     *            提交附加消息
     * @param workingCopy
     *            本地工作副本，可以是文件或文件夹
     * @throws SVNException
     */
    public void commit(String commitMessage, boolean includeChildren, File... workingCopy) throws SVNException {
        SVNCommitClient client = svnClientManager.getCommitClient();
        SVNDepth depth = includeChildren ? SVNDepth.INFINITY : SVNDepth.EMPTY;
        client.doCommit(workingCopy, false, commitMessage, null, null, false, true, depth);
    }

    /**
     * 将文件或文件夹导入版本库而不创建版本化环境
     *
     * @param repoPath
     * @param file
     * @param commitMessage
     * @param includeChildren
     * @throws SVNException
     */
    public void importTo(String repoPath, File file, String commitMessage, boolean includeChildren) throws SVNException {
        SVNCommitClient client = svnClientManager.getCommitClient();
        SVNDepth depth = includeChildren ? SVNDepth.INFINITY : SVNDepth.EMPTY;
        SVNURL url = SVNURL.parseURIEncoded(repoPath);
        client.doImport(file, url, commitMessage, null, true, false, depth);
    }

    /**
     * 将工作副本中的条目移出版本化环境
     *
     * @param workingCopy
     *            需要移出的条目
     * @param deleteMessage
     *            移出附加消息
     * @param deleteFiles
     *            是否从文件系统中删除条目对应的文件
     * @throws SVNException
     */
    public void delete(File workingCopy, String deleteMessage, boolean deleteFiles) throws SVNException {
        SVNWCClient client = svnClientManager.getWCClient();
        client.doDelete(workingCopy, true, deleteFiles, false);
    }

    /**
     * 锁定工作副本和存储库中的文件条目
     *
     * @param workingCopy
     *            需要锁定的文件条目的工作副本
     * @param lockMessage
     *            锁定附加消息
     * @throws SVNException
     */
    public void lock(String lockMessage, File... workingCopy) throws SVNException {
        SVNWCClient client = svnClientManager.getWCClient();
        client.doLock(workingCopy, false, lockMessage);
    }

    /**
     * 解除工作副本和存储库中已锁定的文件条目的锁定状态
     *
     * @param workingCopy
     *            需要解除锁定的文件条目的工作副本
     * @throws SVNException
     */
    public void unlock(File... workingCopy) throws SVNException {
        SVNWCClient client = svnClientManager.getWCClient();
        client.doUnlock(workingCopy, false);
    }

    /**
     * 取消所有本地编辑
     *
     * @param workingCopy
     * @throws SVNException
     */
    public void revert(File... workingCopy) throws SVNException {
        SVNWCClient client = svnClientManager.getWCClient();
        client.doRevert(workingCopy, SVNDepth.INFINITY, null);
    }

    /**
     * 移动/重命名
     *
     * @param src
     * @param dst
     * @throws SVNException
     */
    public void move(File src, File dst) throws SVNException {
        SVNMoveClient client = svnClientManager.getMoveClient();
        client.doMove(src, dst);
    }

    /**
     * 取消移动/重命名
     *
     * @param src
     * @param dst
     * @throws SVNException
     */
    public void undoMove(File src, File dst) throws SVNException {
        SVNMoveClient client = svnClientManager.getMoveClient();
        client.undoMove(src, dst);
        revert(src, dst);
    }

    /**
     * 复制src到dst
     *
     * @param src
     * @param dst
     * @throws SVNException
     */
    public void copy(File dst, File... src) throws SVNException {
        SVNCopyClient client = svnClientManager.getCopyClient();
        SVNCopySource[] sources = new SVNCopySource[src.length];
        int i = 0;
        for (File file : src) {
            sources[i++] = new SVNCopySource(SVNRevision.HEAD, SVNRevision.HEAD, file);
        }
        client.doCopy(sources, dst, false, true, false);
    }

    /**
     * 比较当前工作版本和版本库最新版本的不同，输出到out
     *
     * @param src
     * @param out
     * @throws SVNException
     */
    public void diff(File src, OutputStream out) throws SVNException {
        SVNDiffClient client = svnClientManager.getDiffClient();
        client.doDiff(src, SVNRevision.WORKING, src, SVNRevision.HEAD, SVNDepth.INFINITY, false, out, null);
    }

    public static void main(String[] args) throws Exception {
        SVNUtils svnUtils = new SVNUtils("liuyong12", "xiaoniu@12");
        String uuid = UUIDUtil.getUUID();
        svnUtils.checkout("https://svn-explorer.niudingfeng.com/nbd/001_平台应用系统/05_实时系统/ruleengine/phriskmgmt-service/trunk/phriskmgmt-service/src/main/java/com/xiaoniu/dataplatform/phriskmgmt/utils",
                new File("D:\\svn\\" + uuid),
                true);

        FileUtils.deleteDirectory(new File("D:\\svn\\" + uuid));
    }
}
